#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include "openssl/ssl.h"

int main(int argc, char** argv) {
    SSL_CTX *ctx = NULL;

    char* cert_file = "server.cert";
    char* priv_key = "private.key";

    struct sockaddr_in bind_addr = { 0 };
    struct sockaddr_in peer_addr = { 0 };
    int peer_sock_len = sizeof(struct sockaddr_in);

    int port = 8443;
    bind_addr.sin_family = AF_INET;
    inet_aton("0.0.0.0", &bind_addr.sin_addr);
    bind_addr.sin_port = htons(port);

    // init ssl library
    SSL_library_init();
    // load all algorithm
    OpenSSL_add_all_algorithms();
    // load SSL error strings
    SSL_load_error_strings();

    ctx = SSL_CTX_new(TLS_server_method);
    if (ctx == NULL) {
        printf("failed to ianit ssl ctx");
        return 1;
    }

    // load cert file for server
    int ret = SSL_CTX_use_certificate_file(ctx, cert_file, SSL_FILETYPE_PEM);
    if (ret <= 0) {
        printf("failed to load cert file");
        return 1;
    }

    // load private key
    ret = SSL_CTX_use_PrivateKey_file(ctx, priv_key, SSL_FILETYPE_PEM);
    if (ret <= 0) {
        printf("failed to load private file");
        return 1;
    }

    // check private key file
    SSL_CTX_check_private_key(ctx);

    int svr_sock = socket(AF_INET, SOCK_STREAM, 0);
    bind(svr_sock, &bind_addr, sizeof(bind_addr));

    do {
        listen(svr_sock, 100);

        int new_fd = accept(svr_sock, &peer_addr, &peer_sock_len);
        if (new_fd <= 0) {
            printf("failed to accept socket");
            continue;
        }

        SSL *client = SSL_new(ctx);
        SSL_set_fd(client, new_fd);
        if (SSL_accept(client) <= 0) {
            printf("failed to accept ssl connection");
            continue;
        }

        do {
            char buf[1024] = { 0 };
            size_t real_read = 0;
            int ret = SSL_read_ex(client, buf, 1024, &real_read);

            char *line = NULL;
            sscanf(buf, "%s\n", line);
            printf("%s\n", line);

            if (strcmp(line, "quit") == 0) {
                printf("quit server");
                break;
            }
        } while(1);

        SSL_shutdown(client);
        SSL_free(client);
        close(new_fd);
    } while (1);

    close(svr_sock);
    SSL_CTX_free(ctx);
}
